/**
 * Copyright(c) 2013 Jade Techonologies Co., Ltd.
 *
 * History:
 *   13-4-14 下午3:43 Created by dwzhang
 */
package com.jade.framework.base.criterion;

import java.util.ArrayList;
import java.util.List;

/**
 * Criteria is a simplified API for retrieving entities by composing Criterion objects.
 * This is a very convenient approach for functionality like "search" screens where
 * there is a variable number of conditions to be placed upon the result set.
 *
 * @author dwzhang
 * @version 1.0 13-4-14 下午3:43
 */
public class Criteria implements Criterion
{
    protected List<Criterion> criterions = new ArrayList<Criterion>();
    protected List<Order> orders = new ArrayList<Order>();
    protected List<QueryEntity> entities = new ArrayList<QueryEntity>();
    protected Group group;
    protected Having having;
    protected boolean distinct = false;
    //附加的条件，用于一些特殊的关联
    //protected String additionalCondition;
    /** 偏移量. 默认不进行分页. */
    protected int offset = -1;
    /** 分页长度. 默认不进行分页. */
    protected int length = -1;

    public Criteria()
    {
    }

    public Criteria(int offset, int length)
    {
        this.offset = offset;
        this.length = length;
    }

    /**
     * Add a restriction to constrain the results to be retrieved。
     *
     * @param criterion The criterion object representing the restriction to be applied.
     * @return this (for method chaining)
     */
    public Criteria add(Criterion criterion)
    {
        criterions.add(criterion);
        return this;
    }

    /**
     * 返回所有的条件列表。
     *
     * @return 条件列表。
     */
    public List<Criterion> getCriterions()
    {
        return criterions;
    }

    /**
     * Add a restriction to constrain the results to be retrieved.
     *
     * @param order The criterion object representing the restriction to be applied.
     * @return this (for method chaining)
     */
    public Criteria addOrder(Order order)
    {
        orders.add(order);
        return this;
    }

    /**
     * 返回所有的排序列表。
     *
     * @return 所有的排序列表。
     */
    public List<Order> getOrders()
    {
        return orders;
    }

    /**
     * 以注入的方式支持多表关联查询.
     *
     * @param className  实体类的SimpleName
     * @param entityName entityName，即别名
     */
    public void addEntity(String className, String entityName)
    {
        entities.add(new QueryEntity(className, entityName));
    }

    public void addEntity(String join, String className, String entityName)
    {
        entities.add(new QueryEntity(join, className, entityName));
    }

    /**
     * 获取注入的实体/表名称.
     *
     * @return 获取注入的实体/表名称
     */
    public List<QueryEntity> getEntities()
    {
        return entities;
    }

    public Group getGroup()
    {
        return group;
    }

    public void setGroup(Group group)
    {
        this.group = group;
    }

    public Having getHaving()
    {
        return having;
    }

    public void setHaving(Having having)
    {
        this.having = having;
    }

    public boolean isDistinct()
    {
        return distinct;
    }

    public void setDistinct(boolean distinct)
    {
        this.distinct = distinct;
    }

    public int getOffset()
    {
        return offset;
    }

    public void setOffset(int offset)
    {
        this.offset = offset;
    }

    public int getLength()
    {
        return length;
    }

    public void setLength(int length)
    {
        this.length = length;
    }

    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < criterions.size(); i++) {
            if (i > 0) {
                sb.append(" AND ");
            }
            sb.append("(").append(criterions.get(i)).append(")");
        }

        //        if (StringUtil.isValid(additionalCondition)) {
        //            if (sb.length() > 0) {
        //                sb.append(" AND ");
        //            }
        //            sb.append(additionalCondition);
        //        }

        if (!orders.isEmpty()) {
            sb.append(" ORDER BY ");
        }

        for (int i = 0; i < orders.size(); i++) {
            if (i > 0) {
                sb.append(", ");
            }
            sb.append("(").append(orders.get(i)).append(")");
        }

        if (group != null) {
            sb.append(group);
        }

        if (having != null) {
            sb.append(" ").append(having);
        }

        if (offset > 0) {
            sb.append(" OFFSET:").append(offset);
        }

        if (length > 0) {
            sb.append(" LENGTH:").append(length);
        }

        if (distinct) {
            sb.append(" DISTINCT ");
        }
        return sb.toString();
    }
}
